package kk.json;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import kk.json.parser.BaseJSONParser;
import kk.json.parser.JSONParser;
import kk.json.table.TableInfo;
import kk.json.utils.JSONUtils;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public class JSONDb {

	/** JSONArray缓存。当用户执行read操作，先从Map获取，如果Map没有，则从本地储存获取(本地储存目录在 {@linkplain JSONDb} 初始化时给定)。 */
	public static Map<Class<?>, JSONArray>		jsonMap			= new HashMap<Class<?>, JSONArray>();
	private static Map<Class<?>, JSONParser<?>>	parserMap		= new HashMap<Class<?>, JSONParser<?>>();

	private static JSONParser<?>				defaultParser	= new BaseJSONParser();

	private static String						cacheDir		= "";

	private static JSONDb						instance;
	private static Object						lock			= new Object();

	private JSONDb() {}

	public static JSONDb getInstance() {
		if (instance == null)
			synchronized (lock) {
				if (instance == null)
					instance = new JSONDb();
			}

		return instance;
	};

	/** 初始化缓存目录 */
	public static void initCacheDir(String path) {
		cacheDir = new String(path);
	}

	/**
	 * 添加分析器，执行{@linkplain #insert(Object, boolean)} {@linkplain #queryByCondition(Class, Condition)} 等操作，将使用加入的
	 * {@linkplain JSONParser}
	 */
	public static <T> void addParser(Class<T> clazz, JSONParser<T> parser) {
		parserMap.put(clazz, parser);
	}

	@SuppressWarnings("unchecked")
	public static <T> JSONParser<T> getParser(Class<T> clazz) {
		JSONParser<T> parser = (JSONParser<T>) parserMap.get(clazz);

		if (parser == null) {
			if (defaultParser == null)
				parser = new BaseJSONParser<T>();
			else
				parser = (JSONParser<T>) defaultParser;
		}

		return parser;
	}

	/**
	 * 将对象储存到JSONDB (根据write判断，储存到缓存区还是储存设备)
	 * 
	 * @param object
	 *            需要储存的对象
	 * @param writeToStorage
	 *            if true,写入储存设备;if false,写入缓冲区
	 */
	public <T> void insert(T object, boolean writeToStorage) {
		JSONParser<T> parser = (JSONParser<T>) getParser(object.getClass());
		JSONObject json = parser.parse(object);

		insert(object.getClass(), json, writeToStorage);
	}

	/** 将JSONObject插入到clazz对应JSONArray */
	public <T> void insert(Class<T> clazz, JSONObject json, boolean writeToStorage) {
		JSONArray jsonArray = readJSONArray(clazz);
		jsonArray.put(json);

		write(jsonArray, clazz, writeToStorage);
	}

	/**
	 * @see {@linkplain #insert(Object, boolean)}
	 * */
	public <T> void insert(List<T> list, boolean writeToStorage) {
		for (int i = 0; i < list.size(); i++) {
			insert(list.get(i), writeToStorage);
		}
	}

	/**
	 * @see {@linkplain #insert(Class, JSONObject, boolean))}
	 * */
	public <T> void insert(Class<T> clazz, JSONArray jsonArr, boolean writeToStorage) {
		for (int i = 0; i < jsonArr.length(); i++) {
			try {
				insert(clazz, jsonArr.getJSONObject(i), writeToStorage);
			} catch (JSONException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 删除特定元素
	 * 
	 * @param object
	 *            需要储存的对象
	 * @param writeToStorage
	 *            if true,写入储存设备;if false,写入缓冲区
	 * 
	 * @param condition
	 *            删除条件
	 * 
	 */
	public <T> void delete(Class<T> clazz, boolean writeToStorage, Condition condition) {
		JSONArray jsonArray = readJSONArray(clazz);

		JSONArray newJsonArray = JSONUtils.remove(jsonArray, condition);

		write(newJsonArray, clazz, writeToStorage);
	}

	/***
	 * 删除clazz对应JSONArray
	 * 
	 * @param clazz
	 * @param writeToStorage
	 */
	public <T> void deleteAll(Class<T> clazz, boolean writeToStorage) {
		write(new JSONArray(), clazz, writeToStorage);
	}

	/**
	 * 更新某个元素
	 * 
	 * @param object
	 *            需要更新的对象
	 * 
	 * @param writeToStorage
	 *            if true,写入储存设备; if false,写入缓冲区
	 * 
	 * @param condition
	 */
	public <T> void update(T object, boolean writeToStorage, Condition condition) {
		JSONParser<T> parser = (JSONParser<T>) getParser(object.getClass());

		JSONArray jsonArray = readJSONArray(object.getClass());
		JSONObject updateJson = parser.parse(object);

		JSONArray newJsonArray = JSONUtils.update(jsonArray, updateJson, condition);

		write(newJsonArray, object.getClass(), writeToStorage);
	}

	/**
	 * 查询操作
	 */
	public <T> List<T> queryAll(Class<T> clazz) {
		return queryByCondition(clazz, null);
	}

	/**
	 * 查询操作
	 * 
	 * @param clazz
	 * @param condition
	 * @return
	 */
	public <T> List<T> queryByCondition(Class<T> clazz, Condition condition) {
		JSONParser<T> parser = getParser(clazz);

		List<T> queryList = new ArrayList<T>();

		List<JSONObject> jsonList = JSONUtils.queryByCondition(readJSONArray(clazz), condition);

		for (JSONObject json : jsonList) {
			T t = parser.parse(json, clazz);

			queryList.add(t);
		}

		return queryList;
	}

	/** 获取clazz对应的jsonArray储存路径 */
	public <T> String getJSONArrayPath(Class<T> clazz) {
		String clazzName = TableInfo.getTableName(clazz);

		if (cacheDir != null && !cacheDir.endsWith("/"))
			cacheDir = cacheDir + "/";

		return cacheDir + "jsonArr_" + clazzName + ".json";

	}

	/***
	 * 如果缓冲区存在clazz对应JSONArray，则从缓冲区读取JSONArray；否则从storage读取
	 * 
	 * @param clazz
	 * @return
	 */
	public <T> JSONArray readJSONArray(Class<T> clazz) {
		JSONArray jsonArray = jsonMap.get(clazz);

		if (jsonArray == null) {
			jsonArray = JSONUtils.readJSONArray(getJSONArrayPath(clazz));

			jsonMap.put(clazz, jsonArray);
		}

		return jsonArray;
	}

	/**
	 * 将缓冲区clazz对应缓冲区的JSONArray写到持久层，并清除缓冲区该JSONArray
	 * 
	 * @param jsonArray
	 * @param clazz
	 * @param writeToStorage
	 *            if true,写入持久层;if false,写入缓冲区
	 * 
	 * @return if true,写入持久层成功; if false,jsonArray写入到缓冲区.(false 可能是writeToStorage==false 用户选择写入到缓冲区，也可能是写入持久层失败引起)
	 */
	public boolean write(JSONArray jsonArray, Class<? extends Object> clazz, boolean writeToStorage) {
		boolean successful = false;

		if (writeToStorage) {
			successful = JSONUtils.writeJSONArray(jsonArray, getJSONArrayPath(clazz));

			// 从缓冲区去除
			if (successful)
				jsonMap.remove(clazz);
		}

		// 如果写入storage失败 或 设置了writeToStorage=false，jsonArray仅写入缓冲区
		if (!successful)
			jsonMap.put(clazz, jsonArray);

		return successful;
	}
}
